from models import Place
from tools import getBoundingBox, CoordinateIterator
from osm_service import OSMService, OSMMapDataRequest
from google.appengine.api.labs import taskqueue


class AddPlaceRequest:
    def __init__(self,community_id,name,osmId,lat,lon,categories):
        self.community_id = community_id 
        self.name = name
        self.osmId = osmId
        self.lat = lat
        self.lon = lon
        self.categories = categories  

class POIUpdateScheduleRequest:
    def __init__(self,communityId,lat,lon,radius):
        self.communityId = communityId
        self.lat = float(lat)
        self.lon = float(lon)
        self.radius = float(radius)

class POIUpdateRequest:
    def __init__(self,community,cLat,cLon,radius,pLat,pLon,minLat,minLon,maxLat,maxLon):
        self.community = community
        self.cLat = float(cLat)
        self.cLon = float(cLon)
        self.radius = float(radius)
        self.pLat = float(pLat)
        self.pLon = float(pLon)
        self.minLat = float(minLat)
        self.minLon = float(minLon)
        self.maxLat = float(maxLat)
        self.maxLon = float(maxLon)

class POIUpdateContext:
    def __init__(self,request):
        self.r = request

    def parseContext(self):
        return POIUpdateRequest(self.r["community"],self.r["clat"],self.r["clon"],self.r["r"],self.r["plat"],self.r["plon"],self.r["minlat"],self.r["minlon"], self.r["maxlat"],self.r["maxlon"])

    def isValidRequest(self):
        return self.r.has_key("community") and self.r.has_key("plat") and self.r.has_key("plon") and self.r.has_key("minlat") and self.r.has_key("minlon") and self.r.has_key("maxlat") and self.r.has_key("maxlon")

    @staticmethod
    def buildUrlParams(community,clat,clon,r,plat,plon,minlat,minlon,maxlat,maxlon):
        return "community=%s&clat=%s&clon=%s&r=%s&plat=%s&plon=%s&minlat=%s&minlon=%s&maxlat=%s&maxlon=%s" % (community,clat,clon,r,plat,plon,minlat,minlon,maxlat,maxlon)  

class GetPlacesRequest:
    def __init__(self, community, count=None):
        self.community = community
        self.count = count

class PlaceService:
    def __init__(self):
        pass
    
    def addPlace(self,request):
        p = Place.getPlaceByOSMId(request.osmId)
        if p is not None: return p
        
        p = Place()
        p.name = request.name
        p.osmId = request.osmId
        p.community_id = request.community_id
        p.lat = request.lat
        p.lon = request.lon
        p.categories = request.categories
        p.save()
        return p
    
    def getPlaces(self,request):
        if request.count is None:
            return Place.objects.filter(community_id=request.community).exclude(categories__isnull=True)
        else:
            return Place.objects.filter(community_id=request.community).exclude(categories__isnull=True)[:request.count]
    
    def schedulePOIUpdate(self,request):
        #[minimum-latitude, minimum-longitude, maximum-latitude, maximum-longitude]
        bbox = getBoundingBox(request.lat, request.lon, request.radius)
        lat = bbox[0]
        lon = bbox[1]
        r=[]
        i=0
        
        while True:
            #[lat1,lon1,lat2,lon2]
            iresult = CoordinateIterator(lat, lon, bbox[0], bbox[1], bbox[2], bbox[3]).next()
            if iresult is None: break
            
            r.append({"plat":lat,"plon":lon,"minlat":bbox[0],"minlon":bbox[1] ,"maxlat":bbox[2],"maxlon":bbox[3]})
            
            lat = iresult.nextLat
            lon = iresult.nextLon
            i = i+1
        
            taskqueue.add(url="/places/__task/update-pois/?%s" % POIUpdateContext.buildUrlParams(request.communityId, request.lat, request.lon, request.radius, lat, lon, bbox[0], bbox[1], bbox[2], bbox[3]),method='GET')
        
        return {"clat":request.lat, "clon":request.lon, "r":request.radius, "box":bbox,"requests":r}
        
    def runPOIUpdate(self,request):
        ci = CoordinateIterator(request.pLat, request.pLon, request.minLat, request.minLon, request.maxLat, request.maxLon).next()
        bbox = ci.bBox
        mapService = OSMService()
        data = mapService.getMapData(OSMMapDataRequest(bbox[0], bbox[1], bbox[2], bbox[3]))
        return self.mapData2PlaceModels(request.community, data)
    
    def mapData2PlaceModels(self,community,data):
        places = []
        for d in data:
            #TODO: community_id should be dynamic
            p = self.addPlace(AddPlaceRequest(community, d["name"],d["osmId"],d["lat"], d["lon"], d["tags"].keys()))
            places.append(p)
        return places